package com.lechi.web.controller;

import cn.hutool.json.JSONUtil;
import com.lechi.iot.netty.channel.ITcpChannel;
import com.lechi.iot.netty.utils.BytesToHexUtil;
import com.lechi.web.common.annotation.Anonymous;
import com.lechi.web.common.annotation.Log;
import com.lechi.web.common.annotation.RepeatSubmit;
import com.lechi.web.common.constant.HttpStatus;
import com.lechi.web.common.core.controller.BaseController;
import com.lechi.web.common.core.domain.AjaxResult;
import com.lechi.web.common.core.page.PageDomain;
import com.lechi.web.common.core.page.TableDataInfo;
import com.lechi.web.common.core.page.TableSupport;
import com.lechi.web.common.enums.BusinessType;
import com.lechi.web.common.enums.ErrorCodeEnum;
import com.lechi.web.common.exception.ExceptionUtil;
import com.lechi.web.common.exception.ServiceException;
import com.lechi.web.common.utils.PageUtils;
import com.lechi.web.common.utils.SecurityUtils;
import com.lechi.web.constants.Constants;
import com.lechi.web.framework.util.GuavaCacheUtil;
import com.lechi.web.runner.CacheCmdParseMsg;
import com.lechi.web.runner.SendModbusCmdSchedule;
import com.lechi.web.service.*;
import com.lechi.web.system.domain.*;
import com.lechi.web.system.service.ISysRoleDeviceService;
import com.lechi.web.util.LeChiCacheUtil;
import com.lechi.web.vo.IotDeviceCmdSendVo;
import com.lechi.web.vo.IotDeviceQueryVo;
import com.lechi.web.vo.IotDeviceResult;
import com.lechi.web.vo.IotDeviceVo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 设备 default Controller
 *
 * @author yangguang
 * @date 2024 -03-20
 */
@Slf4j
@RestController
@RequestMapping("/iot/device")
@RequiredArgsConstructor
public class IotDeviceController extends BaseController {

    private final IIotDeviceService iotDeviceService;

    private final IIotDeviceSensorRelService iotDeviceSensorRelService;

    private final IIotDeviceCmdService iotDeviceCmdService;

    private final IIotDeviceTableService iotDeviceTableService;

    private final IIotTriggerRulesService iotTriggerRulesService;

    private final CacheCmdParseMsg cacheCmdParseMsg;

    private final IIotAlertRecordService iotAlertRecordService;

    private final IIotFtpUploadsService iotFtpUploadsService;

    private final IIotWeatherDictService iotWeatherDictService;

    private final SendModbusCmdSchedule sendModbusCmdSchedule;

    @Autowired
    private ISysRoleDeviceService sysRoleDeviceService;

    @NotNull
    private static SysRoleDevice getSysRoleDevice(Long deviceId) {
        SysRoleDevice sysRoleDevice = new SysRoleDevice();
        sysRoleDevice.setRoleId(SecurityUtils.getUserId());
        sysRoleDevice.setDeviceId(deviceId);
        return sysRoleDevice;
    }

    @Anonymous
    @GetMapping("/query")
    //    @PreAuthorize("@ss.hasPermi('iot:device:query')")
    public TableDataInfo query(IotDeviceQueryVo iotDeviceQueryVo) {
        startPage();
        Consumer<IotDeviceBo> search = iotDeviceBo -> {
            iotDeviceBo.setStatus(GuavaCacheUtil.ifTimeOut(String.valueOf(iotDeviceBo.getId()), iotDeviceBo.getTimeInterval()));
        };
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        BeanUtils.copyProperties(iotDeviceQueryVo, iotDeviceBo);
        iotDeviceBo.setProtocolType(String.format("'%s'", String.join("','", Constants.MODBUS_RTU, Constants.WEATHER2017, Constants.WEATHER2024)));
        List<IotDeviceBo> list = iotDeviceService.selectDeviceList(iotDeviceBo);
        list.forEach(search);
        return getDataTable(list);
    }
    /**
     * 查询设备 default 列表
     *
     * @param iotDeviceQueryVo the iot device query vo
     * @return the table data info
     */
    @GetMapping("/list")
    //    @PreAuthorize("@ss.hasPermi('iot:device:query')")
    public TableDataInfo list(IotDeviceQueryVo iotDeviceQueryVo) {
        startPage();
        Consumer<IotDeviceBo> search = iotDeviceBo -> {
            String ifAlarmKey = iotDeviceBo.getId() + "_IF_ALARM";
            Set<Long> alarmsSets = GuavaCacheUtil.getAlarmSensorMap().get(ifAlarmKey);
            iotDeviceBo.setIfAlarm(alarmsSets != null && !alarmsSets.isEmpty());
            iotDeviceBo.setStatus(GuavaCacheUtil.ifTimeOut(String.valueOf(iotDeviceBo.getId()), iotDeviceBo.getTimeInterval()));
        };
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        BeanUtils.copyProperties(iotDeviceQueryVo, iotDeviceBo);
        iotDeviceBo.setProtocolType(String.format("'%s'", String.join("','", Constants.MODBUS_RTU, Constants.WEATHER2017, Constants.WEATHER2024)));
        if (!Objects.isNull(iotDeviceQueryVo.getStatus())) {
            PageDomain pageDomain = TableSupport.buildPageRequest();
            Integer pageNum = pageDomain.getPageNum();
            Integer pageSize = pageDomain.getPageSize();
            PageUtils.clearPage();
            List<IotDeviceBo> list = iotDeviceService.selectIotDeviceList(iotDeviceBo);
            list = list.stream().filter(iotDeviceBo1 -> Objects.equals(GuavaCacheUtil.ifTimeOut(String.valueOf(iotDeviceBo1.getId()), iotDeviceBo1.getTimeInterval()), iotDeviceQueryVo.getStatus())).toList();
            list.forEach(search);
            TableDataInfo rspData = new TableDataInfo();
            rspData.setCode(HttpStatus.SUCCESS);
            rspData.setMsg("查询成功");
            rspData.setRows(list.stream().skip((long) (pageNum - 1) * pageSize).limit(pageSize).toList());
            rspData.setTotal(list.size());
            return rspData;
        }
        List<IotDeviceBo> list = iotDeviceService.selectIotDeviceList(iotDeviceBo);
        list.forEach(search);
        return getDataTable(list);
    }

    /**
     * 获取设备 default 详细信息
     *
     * @param id the id
     * @return the info
     */
    @GetMapping(value = "/sensor/{id}")
    //    @PreAuthorize("@ss.hasPermi('iot:device:query')")
    public AjaxResult getSensorByDeviceId(@PathVariable("id") Long id) {
        IotDeviceBo iotDeviceBo = Optional.ofNullable(iotDeviceService.selectIotDeviceById(id))
                .orElseThrow(() -> new ServiceException(ErrorCodeEnum.NOEXITS_ERROR.getValue(), ErrorCodeEnum.NOEXITS_ERROR.getKey()));
        IotDeviceResult iotDeviceResult = new IotDeviceResult();
        BeanUtils.copyProperties(iotDeviceBo, iotDeviceResult);

        // 获取设备下面关联的要素
        IotDeviceSensorRelBo iotDeviceSensorRelBo = new IotDeviceSensorRelBo();
        iotDeviceSensorRelBo.setDeviceId(id);
        List<IotDeviceSensorBo> deviceSensorList = iotDeviceSensorRelService.selectIotDeviceSensorRelList(iotDeviceSensorRelBo);
        iotDeviceResult.setSensorList(deviceSensorList);
        return success(iotDeviceResult);
    }

    /**
     * 获取设备 default 详细信息
     *
     * @param id the id
     * @return the info
     */
    @GetMapping(value = "/{id}")
    //    @PreAuthorize("@ss.hasPermi('iot:device:query')")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        IotDeviceBo iotDeviceBo = Optional.ofNullable(iotDeviceService.selectIotDeviceById(id))
                .orElseThrow(() -> new ServiceException(ErrorCodeEnum.NOEXITS_ERROR.getValue(), ErrorCodeEnum.NOEXITS_ERROR.getKey()));
        IotDeviceResult iotDeviceResult = new IotDeviceResult();
        BeanUtils.copyProperties(iotDeviceBo, iotDeviceResult);

        // 获取设备下面关联的要素
        IotDeviceSensorRelBo iotDeviceSensorRelBo = new IotDeviceSensorRelBo();
        iotDeviceSensorRelBo.setDeviceId(id);
        List<IotDeviceSensorBo> deviceSensorList = iotDeviceSensorRelService.selectIotDeviceSensorRelList(iotDeviceSensorRelBo);
        iotDeviceResult.setSensorList(deviceSensorList);
        return success(iotDeviceResult);
    }

    /**
     * Send ajax result.
     *
     * @param iotDeviceCmdSendVo the iot device cmd send vo
     * @return the ajax result
     */
    @PostMapping("/send")
    @Log(title = "指令消息发送到设备", businessType = BusinessType.SEND)
    //    @PreAuthorize("@ss.hasPermi('iot:device:add')")
    public AjaxResult send(@RequestBody @Valid IotDeviceCmdSendVo iotDeviceCmdSendVo) {
        String deviceSn = iotDeviceCmdSendVo.getDeviceSn();
        String hostName = GuavaCacheUtil.getBiDeviceSnAndIPMap().get(deviceSn);
        if (Constants.WEATHER2017.equals(iotDeviceCmdSendVo.getProtocolType()) || Constants.WEATHER2024.equals(iotDeviceCmdSendVo.getProtocolType())) {
            hostName = GuavaCacheUtil.getDeviceIdAndIPMap().get(iotDeviceCmdSendVo.getDeviceId());
        }
        log.error("WEATHER-2024设备地址hostName:{}, deviceSn：{}", hostName, deviceSn);
        if (Objects.isNull(hostName) || Objects.equals(deviceSn, hostName)) {
            log.error("指令：{} 发送失败, 设备序列号:{} 没有注册~！", iotDeviceCmdSendVo.getCmd(), deviceSn);
            log.error("WEATHER-2024设备地址{},getDeviceIdAndIPMap：{}", hostName, GuavaCacheUtil.getDeviceIdAndIPMap());
            throw new ServiceException("该设备id未注册，未找到对应设备地址！", 3001);
        }

        ITcpChannel tcpChannel = LeChiCacheUtil.getTcpChannelMap().get(hostName);
        if (tcpChannel == null) {
            log.error("用户发送指令异常，通过设备地址：{} 获取tcpChannel值为空， 请联系工程师解决！", hostName);
            throw new ServiceException("该设备未找到对应tcpChannel,请重启设备再试！", 3002);
        }
        try {
            if (Constants.MODBUS_RTU.equals(iotDeviceCmdSendVo.getProtocolType())) {
                byte[] sendMsg = BytesToHexUtil.hexStrToBinaryStr(iotDeviceCmdSendVo.getCmd());
//                TcpMessage message = new TcpByteArrayMessage(sendMsg);
                ByteBuf byteBuf = Unpooled.wrappedBuffer(sendMsg);
                tcpChannel.send(byteBuf);
            }

            if (Constants.WEATHER2017.equals(iotDeviceCmdSendVo.getProtocolType()) || Constants.WEATHER2024.equals(iotDeviceCmdSendVo.getProtocolType())) {
                log.error("用户发送指令:{}，通过设备地址：{}", iotDeviceCmdSendVo.getCmd(), hostName);
                ByteBuf message = ByteBufAllocator.DEFAULT.buffer();
                message.writeCharSequence(iotDeviceCmdSendVo.getCmd(), Charset.defaultCharset());
                tcpChannel.send(message);
            }
        } catch (Exception e) {
            log.error("用户发送16进制指令异常{} ，请联系工程师解决！", iotDeviceCmdSendVo.getCmd());
            throw new ServiceException("16进制指令解析异常，错误提示：" + e.getMessage(), 3003);
        }
        return success();
    }

    /**
     * 复制设备 default 详细信息
     *
     * @param oldDeviceId the old device id
     * @return the ajax result
     */
    @GetMapping(value = "/copy/{deviceId}")
//    @PreAuthorize("@ss.hasPermi('iot:device:clone')")
    @Log(title = "设备克隆", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult cloneDevice(@PathVariable("deviceId") Long oldDeviceId) {
        IotDeviceBo iotDeviceBo = Optional.ofNullable(iotDeviceService.selectIotDeviceById(oldDeviceId)).orElseThrow(ExceptionUtil.notExitsErrorException);
        String timeString = LocalDateTime.now().format(DateTimeFormatter.ofPattern("_HHmmss"));
        String newDeviceSn = iotDeviceBo.getDeviceSn() + timeString;
        iotDeviceBo.setDeviceSn(newDeviceSn);
        iotDeviceBo.setUserId(SecurityUtils.getUserId());
        iotDeviceBo.setDeviceStation(iotDeviceBo.getDeviceStation() + timeString);
        iotDeviceBo.setDeviceName(iotDeviceBo.getDeviceName() + timeString);
        iotDeviceBo.setStatus(Constants.CLOSE_STATUE);
        iotDeviceService.insertIotDevice(iotDeviceBo);
        Long newDeviceId = iotDeviceBo.getId();
        iotDeviceTableService.createDeviceTable(Constants.MONITOR_DATA_TABLE + newDeviceId);
        log.error("获取用户ID============：{}！", SecurityUtils.getUserId());
        if (!Objects.isNull(SecurityUtils.getUserId())) {
            SysRoleDevice sysRoleDevice = getSysRoleDevice(newDeviceId);
            log.error("sysRoleDevice===========：{}！", JSONUtil.toJsonStr(sysRoleDevice));
            sysRoleDeviceService.batchRoleDevice(List.of(sysRoleDevice));
        }

        GuavaCacheUtil.getBiDeviceSnAndIPMap().putIfAbsent(newDeviceSn, newDeviceSn);
        GuavaCacheUtil.getDeviceIdAndInstrumentIdMap().put(iotDeviceBo.getId(), iotDeviceBo.getInstrumentId());
        GuavaCacheUtil.getDeviceIdAndStationMap().put(String.valueOf(iotDeviceBo.getId()), iotDeviceBo.getDeviceStation());
        IotDeviceSensorRelBo iotDeviceSensorRelBo = new IotDeviceSensorRelBo();
        iotDeviceSensorRelBo.setDeviceId(oldDeviceId);
        List<IotDeviceSensorRelBo> deviceSensorList = iotDeviceSensorRelService.selectIotDeviceSensorRelListByDeviceId(iotDeviceSensorRelBo);
        deviceSensorList.forEach(oldIotDeviceSensorRel -> {
            Long oldIotDeviceSensorRelId = oldIotDeviceSensorRel.getId();
            // 获取设备下面关联的要素
            oldIotDeviceSensorRel.setDeviceId(newDeviceId);
            iotDeviceSensorRelService.insertIotDeviceSensorRel(oldIotDeviceSensorRel);
            Long newIotDeviceSensorRelId = oldIotDeviceSensorRel.getId();

            IotDeviceCmdBo iotDeviceCmdBo = new IotDeviceCmdBo();
            iotDeviceCmdBo.setDeviceId(oldDeviceId);
            iotDeviceCmdBo.setSensorAliasId(oldIotDeviceSensorRelId);
            List<IotDeviceCmdBo> iotDeviceCmdBos = iotDeviceCmdService.selectIotDeviceCmdList(iotDeviceCmdBo);
            iotDeviceCmdBos.forEach(iotDeviceCmdBo1 -> {
                iotDeviceCmdBo1.setDeviceId(newDeviceId);
                iotDeviceCmdBo1.setSensorAliasId(newIotDeviceSensorRelId);
                iotDeviceCmdService.insertIotDeviceCmd(iotDeviceCmdBo1);
            });
            // 获取设备下的关联告警
            IotTriggerRules iotTriggerRules = new IotTriggerRules();
            iotTriggerRules.setDeviceId(oldDeviceId);
            iotTriggerRules.setSensorAliasId(oldIotDeviceSensorRelId);
            List<IotTriggerRules> rulesList = iotTriggerRulesService.selectIotTriggerRulesList(iotTriggerRules);
            rulesList.forEach(oldIotTriggerRules -> {
                oldIotTriggerRules.setDeviceId(newDeviceId);
                oldIotTriggerRules.setSensorAliasId(newIotDeviceSensorRelId);
                iotTriggerRulesService.insertIotTriggerRules(oldIotTriggerRules);
            });
        });

        if (Constants.WEATHER2017.equals(iotDeviceBo.getProtocolType()) || Constants.WEATHER2024.equals(iotDeviceBo.getProtocolType())) {
            IotWeatherDict iotWeatherDict = iotWeatherDictService.selectIotWeatherDictById(oldDeviceId);
            if (iotWeatherDict != null) {
                iotWeatherDict.setDeviceId(newDeviceId);
                iotWeatherDictService.insertIotWeatherDict(iotWeatherDict);
            }
        }
        return success();
    }

    /**
     * 新增设备 default
     *
     * @param iotDeviceVo the iot device vo
     * @return the ajax result
     */
    @RepeatSubmit
    @PostMapping("/add")
    @Log(title = "新增传感器设备操作", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
//    @PreAuthorize("@ss.hasPermi('iot:device:add')")
    public AjaxResult add(@RequestBody @Valid IotDeviceVo iotDeviceVo) {
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        BeanUtils.copyProperties(iotDeviceVo, iotDeviceBo);
        String username = SecurityUtils.getUsername();
        iotDeviceBo.setCreateBy(username);

        iotDeviceService.insertIotDevice(iotDeviceBo);
        if (Constants.WEATHER2017.equals(iotDeviceVo.getProtocolType())) {
            IotWeatherDict iotWeatherDict = new IotWeatherDict();
            iotWeatherDict.setDeviceId(iotDeviceBo.getId());
            iotWeatherDictService.insertIotWeatherDict(iotWeatherDict);
        }

        String tableName = Constants.MONITOR_DATA_TABLE + iotDeviceBo.getId();
        iotDeviceTableService.createDeviceTable(tableName);

        SysRoleDevice sysRoleDevice = getSysRoleDevice(iotDeviceBo.getId());
        sysRoleDeviceService.batchRoleDevice(List.of(sysRoleDevice));

        Optional.ofNullable(iotDeviceVo.getSensorList()).ifPresent(item -> item.forEach(
                iotDeviceSensorRelVo -> {
                    IotDeviceSensorRelBo iotDeviceSensorRelBo = new IotDeviceSensorRelBo();
                    BeanUtils.copyProperties(iotDeviceSensorRelVo, iotDeviceSensorRelBo);
                    iotDeviceSensorRelBo.setDeviceId(iotDeviceBo.getId());
                    iotDeviceSensorRelService.insertIotDeviceSensorRel(iotDeviceSensorRelBo);
                    IotDeviceCmdBo iotDeviceCmdBo = new IotDeviceCmdBo();
                    iotDeviceCmdBo.setDeviceId(iotDeviceBo.getId());
                    iotDeviceCmdBo.setDeviceSn(iotDeviceBo.getDeviceSn());
                    iotDeviceCmdBo.setSensorAliasId(iotDeviceSensorRelBo.getId());
                    iotDeviceCmdService.insertIotDeviceCmd(iotDeviceCmdBo);
                }
        ));
        String deviceSn = iotDeviceVo.getDeviceSn();
        GuavaCacheUtil.getBiDeviceSnAndIPMap().putIfAbsent(deviceSn, deviceSn);
        GuavaCacheUtil.getDeviceIdAndInstrumentIdMap().put(iotDeviceBo.getId(), iotDeviceBo.getInstrumentId());
        GuavaCacheUtil.getDeviceIdAndStationMap().put(String.valueOf(iotDeviceBo.getId()), iotDeviceBo.getDeviceStation());
        cacheCmdParseMsg.run(iotDeviceVo.getProtocolType());
        return success();
    }

    /**
     * 修改设备 default
     *
     * @param iotDeviceVo the iot device vo
     * @return the ajax result
     */
    @RepeatSubmit
    @PostMapping("/edit")
    @Log(title = "修改设备操作", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
//    @PreAuthorize("@ss.hasPermi('iot:device:edit')")
    public AjaxResult edit(@RequestBody @Valid IotDeviceVo iotDeviceVo) {
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        String username = SecurityUtils.getUsername();
        BeanUtils.copyProperties(iotDeviceVo, iotDeviceBo);
        iotDeviceBo.setUpdateBy(username);

        iotDeviceVo.getSensorList().forEach(iotDeviceSensorRelVo -> {
            IotDeviceSensorRelBo iotDeviceSensorRelBo = new IotDeviceSensorRelBo();
            BeanUtils.copyProperties(iotDeviceSensorRelVo, iotDeviceSensorRelBo);

            if (Objects.equals(iotDeviceSensorRelVo.getId(), Constants.ADD_FLAG)) {
                iotDeviceSensorRelService.insertIotDeviceSensorRel(iotDeviceSensorRelBo);
                IotDeviceCmdBo iotDeviceCmdBo = new IotDeviceCmdBo();
                iotDeviceCmdBo.setIsHide(iotDeviceSensorRelBo.getIsHide());
                iotDeviceCmdBo.setDeviceId(iotDeviceVo.getId());
                iotDeviceCmdBo.setDeviceSn(iotDeviceVo.getDeviceSn());
                iotDeviceCmdBo.setSensorGroupId(iotDeviceSensorRelBo.getSensorGroupId());
                iotDeviceCmdBo.setSensorAliasId(iotDeviceSensorRelBo.getId());
                iotDeviceCmdBo.setSort(iotDeviceSensorRelBo.getSort());
                iotDeviceCmdBo.setIntFactor(iotDeviceSensorRelBo.getIntFactor());
                iotDeviceCmdService.insertIotDeviceCmd(iotDeviceCmdBo);
            } else {
                iotDeviceSensorRelService.updateIotDeviceSensorRel(iotDeviceSensorRelBo);
                IotDeviceCmdBo iotDeviceCmdBo = new IotDeviceCmdBo();
                iotDeviceCmdBo.setSensorGroupId(iotDeviceSensorRelBo.getSensorGroupId());
                iotDeviceCmdBo.setSensorAliasId(iotDeviceSensorRelBo.getId());
                iotDeviceCmdBo.setSort(iotDeviceSensorRelBo.getSort());
                iotDeviceCmdBo.setIntFactor(iotDeviceSensorRelBo.getIntFactor());
                iotDeviceCmdService.updateIotCmdByAliasId(iotDeviceCmdBo);
            }
        });
        String deviceSnNew = iotDeviceVo.getDeviceSn();
        iotDeviceService.updateIotDevice(iotDeviceBo);

        GuavaCacheUtil.getBiDeviceSnAndIPMap().putIfAbsent(deviceSnNew, deviceSnNew);
        GuavaCacheUtil.getDeviceIdAndInstrumentIdMap().put(iotDeviceBo.getId(), iotDeviceBo.getInstrumentId());
        GuavaCacheUtil.getDeviceIdAndStationMap().forcePut(String.valueOf(iotDeviceBo.getId()), iotDeviceBo.getDeviceStation());
        cacheCmdParseMsg.run(iotDeviceVo.getProtocolType());
        return AjaxResult.success();
    }

    /**
     * 删除设备 default
     *
     * @param ids the ids
     * @return the ajax result
     */
    @DeleteMapping("/{ids}")
    @Log(title = "删除设备", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
//    @PreAuthorize("@ss.hasPermi('iot:device:remove')")
    public AjaxResult remove(@PathVariable Long[] ids) {
        Arrays.stream(ids).forEach(deviceId -> {
            sendModbusCmdSchedule.run(String.valueOf(deviceId));
            IotDeviceSensorRelBo iotDeviceSensorRelBo = new IotDeviceSensorRelBo();
            iotDeviceSensorRelBo.setDeviceId(deviceId);
            iotDeviceSensorRelService.deleteIotDeviceSensorRelByDeviceId(deviceId);
            iotDeviceCmdService.deleteIotDeviceCmdByDeviceId(deviceId);
            iotTriggerRulesService.deleteIotTriggerRulesByDeviceId(deviceId);
            IotDeviceBo iotDeviceBo = iotDeviceService.selectIotDeviceById(deviceId);

            iotDeviceTableService.dropDeviceTable(Constants.MONITOR_DATA_TABLE + iotDeviceBo.getId());
            iotAlertRecordService.deleteIotAlertRecordByDeviceId(deviceId);

            IotFtpUploads iotFtpUploads = new IotFtpUploads();
            iotFtpUploads.setDeviceStation(iotDeviceBo.getDeviceStation());
            iotFtpUploadsService.deleteIotFtpUploadsByParams(iotFtpUploads);

            // 删除告警规则缓存
            IotTriggerRules iotTriggerRules = new IotTriggerRules();
            iotTriggerRules.setDeviceId(deviceId);
            iotTriggerRulesService.cleanCacheAlarmRule(iotTriggerRules);

        });
        iotWeatherDictService.deleteIotWeatherDictByIds(ids);
        iotDeviceService.deleteIotDeviceByIds(ids);
        sysRoleDeviceService.deleteRoleDevice(ids);
        return AjaxResult.success();
    }

    /**
     * 加载对应角色设备列表树
     *
     * @param roleId the role id
     * @return the ajax result
     */
    @GetMapping(value = "/roleDeviceTree/{roleId}")
    public AjaxResult roleMenuTreeSelect(@PathVariable("roleId") Long roleId) {
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
//        iotDeviceBo.setProtocolType(String.format("'%s'", String.join("','", Constants.MODBUS_RTU, Constants.WEATHER2017, Constants.WEATHER2024)));
        final List<IotDeviceBo> iotDeviceBoList = iotDeviceService.selectIotDeviceList(iotDeviceBo);
        final Map<String, List<IotDeviceBo>> collect = iotDeviceBoList.stream().collect(Collectors.groupingBy(IotDeviceBo::getGroupName));
        AtomicInteger num = new AtomicInteger(1);
        final List<Map<String, Object>> list = collect.entrySet().stream().map(entry -> {
            Map<String, Object> map = new HashMap<>();
            map.put("deviceGroupId", num.getAndIncrement());
            map.put("deviceGroupName", entry.getKey());
            map.put("deviceData", entry.getValue());
            return map;
        }).toList();
        AjaxResult ajax = AjaxResult.success();

        ajax.put("checkedKeys", iotDeviceService.selectDeviceListByRoleId(roleId));
        ajax.put("devices", list);
        return ajax;
    }


    /**
     * 加载对应角色设备列表树
     *
     * @param deviceIds the device ids
     * @return the ajax result
     */
    @GetMapping(value = "/sameSensor/{deviceIds}")
    public AjaxResult sameSensor(@PathVariable("deviceIds") Long[] deviceIds) {
        if (deviceIds.length == 1) {
            IotDeviceSensorRelBo iotDeviceGroupRel = new IotDeviceSensorRelBo();
            iotDeviceGroupRel.setDeviceId(deviceIds[0]);
            List<IotDeviceSensorRelBo> retList = iotDeviceSensorRelService.selectIotDeviceSensorRelListByDeviceId(iotDeviceGroupRel);
            return AjaxResult.success(retList);
        }

        List<IotDeviceSensorsBo> resultDeviceSensorRelBoList = Lists.newArrayList();
        String sensorIds = null;
        List<IotDeviceSensorsBo> iotDeviceSensorRelBoList = null;
        for (Long id : deviceIds) {
            iotDeviceSensorRelBoList = querySensor(id, sensorIds, 1);
            if (iotDeviceSensorRelBoList.isEmpty()) {
                return AjaxResult.success(new ArrayList<>());
            }
            sensorIds = iotDeviceSensorRelBoList.stream().map(IotDeviceSensorsBo::getSensorId).distinct().map(String::valueOf).collect(Collectors.joining(","));
        }
        final String finalSensor = sensorIds;
        Arrays.asList(deviceIds).forEach(deviceId -> {
            resultDeviceSensorRelBoList.addAll(querySensor(deviceId, finalSensor, 0));
        });
        return AjaxResult.success(resultDeviceSensorRelBoList);
    }

    private List<IotDeviceSensorsBo> querySensor(Long deviceId, String sensorIds, Integer alarmCount) {
        IotDeviceSensorRelBo iotDeviceSensorRelBo = new IotDeviceSensorRelBo();
        iotDeviceSensorRelBo.setDeviceId(deviceId);
        iotDeviceSensorRelBo.setSensorAliasName(sensorIds);
        iotDeviceSensorRelBo.setAlarmCount(alarmCount);
        return iotDeviceSensorRelService.selectByDeviceIdAndSensorId(iotDeviceSensorRelBo);
    }
}
